package com.jh.paymentchannel.util.ainong;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Value;

import sun.misc.BASE64Decoder;

import com.jnewsdk.connection.client.HttpClient;
import com.jnewsdk.connection.client.HttpSSLClient;
import com.jnewsdk.tools.log.LogFactory;
import com.jnewsdk.util.Base64;
import com.jnewsdk.util.ResourceUtil;
import com.jnewsdk.util.SignUtil;
import com.jnewsdk.util.StringUtils;

public class BaseServlet extends HttpServlet {
	@Value("${ailong.key}")
	private String merKey;
	// ��������Base64����
	private final String[] base64Keys = new String[] { "subject", "body", "remark" };
	// ��������Base64���ܣ� �����������json���ݸ�ʽ
	private final String[] base64JsonKeys = new String[] { "customerInfo", "accResv", "riskRateInfo", "billQueryInfo",
			"billDetailInfo" };
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -4182430881185073890L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	/**
	 * ��mapת��Ϊ����key1=value1&key2=value2...
	 * 
	 * @param map
	 * @return
	 */
	protected String getWebForm(Map<String, String> map) {
		if (null == map || map.keySet().size() == 0) {
			return "";
		}

		StringBuffer url = new StringBuffer();
		for (Map.Entry<String, String> entry : map.entrySet()) {
			String value = entry.getValue();
			String str = (value != null ? value : "");
			try {
				str = URLEncoder.encode(str, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			url.append(entry.getKey()).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);
		}

		// ���һ����ֵ�Ժ���ġ�&����Ҫȥ����
		String strURL = "";
		strURL = url.toString();
		if (URL_PARAM_CONNECT_FLAG.equals("" + strURL.charAt(strURL.length() - 1))) {
			strURL = strURL.substring(0, strURL.length() - 1);
		}
		return (strURL);
	}

	/**
	 * ����ǩ��
	 * 
	 * @param paramMap
	 */
	public void setSignature(Map<String, String> paramMap) {
		String key = merKey;
		String signMethod = paramMap.get("signMethod");

		Set<String> removeKey = new HashSet<String>();
		removeKey.add("signMethod");
		removeKey.add("signature");
		String signMsg = SignUtil.getSignMsg(paramMap, removeKey);
		if("RSA".equals(signMethod)){
			key = ResourceUtil.getString("paytest", "RSAkey");
			try {
				String signature = sign(signMsg.getBytes("UTF-8"),key);
				paramMap.put("signature", signature);
			} catch (Exception e) {
				LogFactory.getLog().error(e, e.getMessage());
			}
		}else{
			String signature = SignUtil.sign(signMethod, signMsg, key, "UTF-8");
			paramMap.put("signature", signature);
		}
	}

	/**
     * ��˽Կ����Ϣ��������ǩ��
     * @param data   //��������
     * @param privateKey //˽Կ
     * @return
     * @throws Exception
     */
	protected static String sign(byte[] data,String privateKey)throws Exception{
        //����˽Կ
        byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(privateKey);
        //����PKCS8EncodedKeySpec����
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        //ָ�������㷨
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //ȡ˽Կ�׶���
        PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //��˽Կ����Ϣ��������ǩ��
        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initSign(privateKey2);
        signature.update(data);
         
        return new String(Base64.encode(signature.sign()));
    }
	/**
	 * ��������������
	 * 
	 * @param url
	 *            ͨѶ��ַ
	 * @param paramMap
	 *            ���Ͳ���
	 * @return Ӧ����Ϣ
	 */
	public String sendMsg(String url, Map<String, String> paramMap) {
		try {
			HttpClient http = new HttpSSLClient(url, "60000");
			http.setRequestMethod("POST");
//			http.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.connect();
			// ת��������ʽ
			String webForm = getWebForm(paramMap);
			http.send(webForm.getBytes());
			byte[] rspMsg = http.getRcvData();
			String msg = new String(rspMsg, "utf-8");
			LogFactory.getLog().info(this, msg);
			return msg;
		} catch (Exception e) {
			LogFactory.getLog().error(e, e.getMessage());
		}
		return null;
	}

	/**
	 * ת�����ĸ�ʽ�������ֶ�base64����
	 * 
	 * @param msg
	 * @return
	 */
	public Map parseMsg(String msg) {
		Map map = SignUtil.parseResponse(msg);
		// �����ֶ�base64����
		for (Iterator iterator = base64Key.iterator(); iterator.hasNext();) {
			String key = (String) iterator.next();
			String value = (String) map.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.decode(value.toCharArray()), "UTF-8");
					map.put(key, text);
				} catch (Exception e) {
				}
			}
		}
		return map;
	}

	/**
	 * BASE64����
	 * 
	 * @param data
	 * @return
	 */
	public String base64encode(String data) {
		try {
			return new String(Base64.encode(data.getBytes("UTF-8")));
		} catch (Exception e) {
			LogFactory.getLog().error(this, e);
			return data;
		}
	}

	/**
	 * BASE64����
	 * 
	 * @param data
	 * @return
	 */
	public String base64decode(String data) {
		try {
			return new String(Base64.decode(data.toCharArray()), "UTF-8");
		} catch (Exception e) {
			LogFactory.getLog().error(this, e);
			return data;
		}
	}

	/**
	 * ��ǩ
	 * 
	 * @param paramMap
	 * @return
	 */
	public boolean verifySign(Map paramMap) {
		// ����ǩ��
		Set<String> removeKey = new HashSet<String>();
		removeKey.add("signMethod");
		removeKey.add("signature");
		String signedMsg = SignUtil.getSignMsg(paramMap, removeKey);
		String signMethod = (String) paramMap.get("signMethod");
		String signature = (String) paramMap.get("signature");
		// ��Կ
		String key = merKey;
		if("RSA".equals(signMethod)){
			String RSAPubKey=ResourceUtil.getString("paytest", "RSAPubKey");
			return doCheck(signedMsg,signature,RSAPubKey,"UTF-8");
		}
		return SignUtil.verifySign(signMethod, signedMsg, signature, key, "UTF-8");
	}
	/**
	 * RSA��ǩ�����
	 * 
	 * @param content
	 *            ��ǩ������
	 * @param sign
	 *            ǩ��ֵ
	 * @param publicKey
	 *            ����������̹�Կ
	 * @param encode
	 *            �ַ�������
	 * @return ����ֵ
	 */
	public static boolean doCheck(String content, String sign, String publicKey, String encode) {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = (new BASE64Decoder()).decodeBuffer(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

			Signature signature = Signature.getInstance("SHA1WithRSA");

			signature.initVerify(pubKey);
			signature.update(content.getBytes(encode));

			boolean bverify = signature.verify(Base64.decode(sign.toCharArray()));
			return bverify;
		} catch (Exception e) {
			LogFactory.getLog().error(BaseServlet.class, e);
		}
		return false;
	}
	public void converData(Map paramMap) {
		for (int i = 0; i < base64Keys.length; i++) {
			String key = base64Keys[i];
			String value = (String) paramMap.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.encode(value.getBytes("UTF-8")));
					// �����������
					paramMap.put(key, text);
				} catch (Exception e) {
				}
			}
		}
		for (int i = 0; i < base64JsonKeys.length; i++) {
			String key = base64JsonKeys[i];
			String value = (String) paramMap.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.encode(value.getBytes("UTF-8")));
					// �����������
					paramMap.put(key, text);
				} catch (Exception e) {
				}
			}
		}
	}

	private static final String URL_PARAM_CONNECT_FLAG = "&";
	public static final Set<String> base64Key = new HashSet<String>();
	static {
		base64Key.add("subject");
		base64Key.add("body");
		base64Key.add("remark");
		base64Key.add("customerInfo");
		base64Key.add("accResv");
		base64Key.add("riskRateInfo");
		base64Key.add("billpQueryInfo");
		base64Key.add("billDetailInfo");
		base64Key.add("respMsg");
		base64Key.add("resv");
	}
}
